﻿using In66.Net.EventBus.RabbitMq.Attributes;
using In66.Net.EventBus.RabbitMq.IIntegration;
using Microsoft.Extensions.DependencyModel;
using System.ComponentModel;
using System.Reflection;

namespace In66.Net.EventBus.RabbitMq;

public static class IntegrationEventExtension
{
    private static readonly string[] Filters = { "dotnet-", "Microsoft.", "mscorlib", "netstandard", "System", "Windows" };
    private static readonly IEnumerable<Assembly>? _allAssemblies;
    private static readonly IEnumerable<Type>? _allTypes;

    /// <summary>
    /// 需要排除的项目
    /// </summary>
    private static readonly List<string> FilterLibs = new();

    /// <summary>
    /// 构造函数
    /// </summary>
    static IntegrationEventExtension()
    {
        _allAssemblies = DependencyContext.Default?.GetDefaultAssemblyNames().Where(c => c.Name is not null && !Filters.Any(c.Name.StartsWith) && !FilterLibs.Any(c.Name.StartsWith)).Select(Assembly.Load);
        _allTypes = _allAssemblies?.SelectMany(c => c.GetTypes());
    }

    #region tools

    /// <summary>
    /// 查找指定条件的类型
    /// </summary>
    public static IEnumerable<Type> FindTypes(Func<Type, bool> predicate) => _allTypes!.Where(predicate).ToArray();

    /// <summary>
    /// 返回当前类型是否是指定基类的派生类
    /// </summary>
    /// <param name="type">当前类型</param>
    /// <param name="baseType">要判断的基类型</param>
    /// <returns></returns>
    public static bool IsBaseOn(this Type type, Type baseType) => baseType.IsGenericTypeDefinition ? type.HasImplementedRawGeneric(baseType) : baseType.IsAssignableFrom(type);

    /// <summary>
    /// 判断指定的类型 <paramref name="type" /> 是否是指定泛型类型的子类型，或实现了指定泛型接口。
    /// </summary>
    /// <param name="type">需要测试的类型。</param>
    /// <param name="generic">泛型接口类型，传入 typeof(IXxx&lt;&gt;)</param>
    /// <returns>如果是泛型接口的子类型，则返回 true，否则返回 false。</returns>
    public static bool HasImplementedRawGeneric(this Type type, Type generic)
    {
        type.NotNull(nameof(type));
        generic.NotNull(nameof(generic));
        // 测试接口。
        var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType);
        if (isTheRawGenericType)
        {
            return true;
        }
        // 测试类型。
        while (type != typeof(object))
        {
            isTheRawGenericType = IsTheRawGenericType(type);
            if (isTheRawGenericType)
            {
                return true;
            }

            type = type.BaseType!;
        }
        // 没有找到任何匹配的接口或类型。
        return false;

        // 测试某个类型是否是指定的原始接口。
        bool IsTheRawGenericType(Type test) => generic == (test.IsGenericType ? test.GetGenericTypeDefinition() : test);
    }

    /// <summary>
    /// 检查参数不能为空引用，否则抛出<see cref="ArgumentNullException" />异常。
    /// </summary>
    /// <param name="value"></param>
    /// <param name="paramName">参数名称</param>
    /// <exception cref="ArgumentNullException"></exception>
    public static void NotNull<T>(this T value, string paramName) => Require<ArgumentNullException>(value is not null, $"参数“{paramName}”不能为空引用。");

    /// <summary>
    /// 验证指定值的断言<paramref name="assertion" />是否为真，如果不为真，抛出指定消息<paramref name="message" />的指定类型<typeparamref name="TException" />异常
    /// </summary>
    /// <typeparam name="TException">异常类型</typeparam>
    /// <param name="assertion">要验证的断言。</param>
    /// <param name="message">异常消息。</param>
    public static void Require<TException>(bool assertion, string message) where TException : Exception
    {
        if (assertion)
        {
            return;
        }
#if NET7_0_OR_GREATER
        ArgumentException.ThrowIfNullOrEmpty(message, nameof(message));
#else
        if (string.IsNullOrWhiteSpace(message))
        {
            throw new ArgumentNullException(nameof(message));
        }
#endif
        throw (TException)Activator.CreateInstance(typeof(TException), message)!;
    }

    /// <summary>
    /// 转成显示名字
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    internal static string? ToDescription(this Enum value)
    {
        var member = value.GetType().GetMember(value.ToString()).FirstOrDefault();
        return member?.ToDescription();
    }

    /// <summary>
    /// 获取描述或者显示名称
    /// </summary>
    /// <param name="member"></param>
    /// <returns></returns>
    internal static string ToDescription(this MemberInfo member)
    {
        var desc = member.GetCustomAttribute<DescriptionAttribute>();
        if (desc is not null)
        {
            return desc.Description;
        }
        //显示名
        var display = member.GetCustomAttribute<DisplayNameAttribute>();
        return display is not null ? display.DisplayName : member.Name;
    }

    /// <summary>
    /// 判断特性相应是否存在
    /// </summary>
    /// <typeparam name="T">动态类型要判断的特性</typeparam>
    /// <param name="memberInfo"></param>
    /// <param name="inherit"></param>
    /// <returns>如果存在还在返回true，否则返回false</returns>
    public static bool HasAttribute<T>(this MemberInfo memberInfo, bool inherit = true) where T : Attribute => memberInfo.IsDefined(typeof(T), inherit);

    /// <summary>
    /// 具有相匹配的通用类型
    /// </summary>
    /// <param name="interfaceType">接口类型</param>
    /// <param name="typeInfo">对象类型</param>
    /// <returns></returns>
    public static bool HasMatchingGenericArity(this Type interfaceType, TypeInfo typeInfo)
    {
        if (!typeInfo.IsGenericType)
        {
            return true;
        }

        var interfaceTypeInfo = interfaceType.GetTypeInfo();
        if (!interfaceTypeInfo.IsGenericType)
        {
            return false;
        }

        var argumentCount = interfaceType.GenericTypeArguments.Length;
        var parameterCount = typeInfo.GenericTypeParameters.Length;
        return argumentCount == parameterCount;
    }

    #endregion


    /// <summary>
    /// 获取Header的属性
    /// </summary>
    /// <param name="event"></param>
    /// <returns></returns>
    internal static IDictionary<string, object>? GetHeaderAttributes(this IIntegrationEvent @event)
    {
        var type = @event.GetType();
        var rabbitHeaderAttributes = type.GetCustomAttributes<RabbitHeaderAttribute>();
        return RabbitDictionariesByDic(rabbitHeaderAttributes);
    }

    /// <summary>
    /// 获取交换机的Arguments
    /// </summary>
    /// <param name="event"></param>
    /// <returns></returns>
    internal static IDictionary<string, object>? GetExchangeArgAttributes(this IIntegrationEvent @event)
    {
        var type = @event.GetType();
        var exchangeArgs = type.GetCustomAttributes<RabbitExchangeArgAttribute>();
        return RabbitDictionariesByDic(exchangeArgs);
    }

    /// <summary>
    /// 获取交换机的Arguments
    /// </summary>
    /// <param name="eventType"></param>
    /// <returns></returns>
    internal static IDictionary<string, object>? GetExchangeArgAttributes(this Type eventType)
    {
        var exchangeArgs = eventType.GetCustomAttributes<RabbitExchangeArgAttribute>();
        return RabbitDictionariesByDic(exchangeArgs);
    }

    /// <summary>
    /// 获取交换机的Arguments
    /// </summary>
    /// <param name="event"></param>
    /// <returns></returns>
    internal static IDictionary<string, object>? GetQueueArgAttributes(this IIntegrationEvent @event)
    {
        var type = @event.GetType();
        var queueArgs = type.GetCustomAttributes<RabbitQueueArgAttribute>();
        return RabbitDictionariesByDic(queueArgs);
    }

    /// <summary>
    /// 获取交换机的Arguments
    /// </summary>
    /// <param name="eventType"></param>
    /// <returns></returns>
    internal static IDictionary<string, object>? GetQueueArgAttributes(this Type eventType)
    {
        var queueArgs = eventType.GetCustomAttributes<RabbitQueueArgAttribute>();
        return RabbitDictionariesByDic(queueArgs);
    }

    /// <summary>
    /// 将特性内容转换成字典
    /// </summary>
    /// <param name="rabbitDictionaryAttributes"></param>
    /// <returns></returns>
    private static Dictionary<string, object>? RabbitDictionariesByDic(this IEnumerable<RabbitDictionaryAttribute>? rabbitDictionaryAttributes)
    {
        return rabbitDictionaryAttributes?.ToDictionary(rabbitDictionaryAttribute => rabbitDictionaryAttribute.Key,
            rabbitDictionaryAttribute => rabbitDictionaryAttribute.Value);
    }
}